package cn.apotato.common.base.controller;

import cn.apotato.common.base.enums.DesensitizationMode;
import cn.apotato.common.base.function.*;
import cn.apotato.common.base.listener.BaseReadListener;
import cn.apotato.common.base.service.BaseService;
import cn.apotato.common.cache.interfaces.Cache;
import cn.apotato.common.model.base.BaseModel;
import cn.apotato.common.model.base.Model;
import cn.hutool.core.util.IdUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.util.MapUtils;
import com.alibaba.fastjson2.JSON;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.IService;
import com.github.yulichang.extension.mapping.base.MPJDeepService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.Map;


/**
 * 基本控制器
 *
 * @author 胡晓鹏
 * @date 2023/04/21
 */
@Slf4j
public abstract class BaseController<T extends Model, ID> {

    protected final IService<T> iService;
    protected final BaseMapper<T> mapper;
    protected final BaseService<T, ID> service;
    protected final Cache cache;

    public BaseController(MPJDeepService<T> iService, BaseMapper<T> mapper, Cache cache) {
        this.iService = iService;
        this.mapper = mapper;
        this.cache = cache;
        this.service = new BaseService<>(iService, mapper, cache);
    }

    /**
     * 创建
     *
     * @param entity 实体
     * @return {@link T}
     */
    @PostMapping
    public T create(@RequestBody T entity) {
        return service.save(entity);
    }

    /**
     * 发现通过id
     *
     * @param id id
     * @return {@link T}
     */
    @GetMapping("/{id}")
    public T findById(@PathVariable("id") ID id) {
        return service.findById(id);
    }

    /**
     * 找到页面
     *
     * @param page   页面
     * @param entity 实体
     * @return {@link IPage}<{@link T}>
     * @throws IllegalAccessException 非法访问异常
     */
    @GetMapping
    public Page<T> page(Page<T> page, T entity) throws IllegalAccessException {
        return service.page(page, entity, setQueryParamHook(entity), setQueryWrapperHook(entity), setResultFilterHook(), setListFilterHookFunction(), setObjectFilterHook(), DesensitizationMode.SELECT);
    }


    /**
     * 更新
     *
     * @param entity 实体
     * @return {@link T}
     */
    @PutMapping
    public T update(@RequestBody T entity) {
        return service.update(entity);
    }

    /**
     * 删除通过id
     *
     * @param id id
     */
    @DeleteMapping("/{id}")
    public void deleteById(@PathVariable("id") ID id) {
        service.deleteById(id);
    }



    @GetMapping("/export")
    public void exporting(Page<T> page, T entity, String fileName, HttpServletResponse response) throws IOException, IllegalAccessException {
        try {
            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("utf-8");
            // 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
            fileName = StringUtils.isNotBlank(fileName) ? fileName : URLEncoder.encode(IdUtil.fastSimpleUUID(), "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
            // 查询数据
            page = exportDataProcessing(
                    service.page(page, entity,
                            setQueryParamHook(entity),
                            setQueryWrapperHook(entity),
                            setResultFilterHook(),
                            setListFilterHookFunction(),
                            setObjectFilterHook(),
                            DesensitizationMode.EXPORT
                    )
            );
            EasyExcel.write(response.getOutputStream(), iService.getEntityClass()).sheet("sheet").doWrite(page.getRecords());
        } catch (Exception e) {
            // 重置response
            response.reset();
            response.setContentType("application/json");
            response.setCharacterEncoding("utf-8");
            Map<String, String> map = MapUtils.newHashMap();
            map.put("status", "failure");
            map.put("message", "下载文件失败" + e.getMessage());
            response.getWriter().println(JSON.toJSONString(map));
        }

    }

    @PostMapping("/import")
    @ResponseBody
    public String importing(MultipartFile file) throws IOException {
        EasyExcel.read(file.getInputStream(), iService.getEntityClass(), new BaseReadListener<>(service)).sheet().doRead();
        return "success";
    }


    /**
     * 出口数据处理
     *
     * @param page 页面
     * @return {@link Page}<{@link T}>
     */
    public Page<T> exportDataProcessing(Page<T> page) {
        return page;
    }


    /**
     * 设置查询参数钩
     *
     * @return {@link QueryParamHookFunction}<{@link T}>
     */
    public QueryParamHookFunction<T> setQueryParamHook(T entity) {
        return t -> entity;
    }

    /**
     * 设置查询参数钩子函数
     *
     * @return {@link QueryWrapperHookFunction}<{@link T}>
     */
    public QueryWrapperHookFunction<T> setQueryWrapperHook(T entity) {
        return lambdaQueryWrapper -> lambdaQueryWrapper;
    }

    /**
     * 设置结果过滤钩子
     *
     * @return {@link ResultPageFilterHookFunction}<{@link T}>
     */
    public ResultPageFilterHookFunction<T> setResultFilterHook() {
        return page -> page;
    }

    /**
     * 设置列表过滤钩子函数
     *
     * @return {@link ResultListFilterHookFunction}<{@link T}>
     */
    public ResultListFilterHookFunction<T> setListFilterHookFunction() {
        return records -> records;
    }

    /**
     * 查询结果过滤钩子
     *
     * @return {@link ResultObjectFilterHook}<{@link T}>
     */
    public ResultObjectFilterHook<T> setObjectFilterHook() {
        return object -> object;
    }

}
